/*********************************************
 * Our map that we create based on views given to us.
 * Used in the a* search. 160*160 cause we know the game
 * map won't exceed 80*80.
 */

import java.awt.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;


/**
 * 
 * Agent has a map.
 *
 */
public class Map {
	
	public static final int LEFT = 0;
	public static final int UP = 1;
	public static final int RIGHT = 2;
	public static final int DOWN = 3;
	
	private char myMap[][];
	//convert number into direction character for printing. No other use
	private char[] direction = {'<', '^', '>', 'v'};
	
	public int Top = 78;
	public int Left = 78;
	public int Right = 82;
	public int Bottom = 82;


	public Map(){
		this.myMap = new char[160][160];
		//Initialize map, get rid of junk data
		//! = unknown
		int i,j;
		for(i = 0; i < 160; i++) {
			for (j = 0; j < 160; j++) {
				myMap[i][j] = '!';
			}
		}
	}
	
	public Map (Map masterCopy){
		this.myMap = new char[160][160];
		
		for(int i = 0; i < 160; i++) {
			for (int j = 0; j < 160; j++) {
				this.myMap[i][j] = masterCopy.getMyMap()[i][j];
			}
		}
	}

	void printMap(int agentDirection)
	{
		int i,j;

		System.out.println("\n+-----+");
		for( i=0; i < 160; i++ ) {
			System.out.print("|");
			for( j=0; j < 160; j++ ) {
				if(( i == (Top+Bottom)/2 )&&( j == (Left+Right)/2 )) {
					System.out.print(direction[agentDirection]);
				}
				else {
					System.out.print( myMap[i][j] );
				}
			}
			System.out.println("|");
		}
		System.out.println("+-----+");
	}

	public void updateMap(char[][] view, int agentDirection){

		//lot of redundancy here but might be a safer approach
		if(agentDirection == 1) {
			int i, j;
			for(i = 0; i < 5; i++) {
				for(j = 0; j < 5; j++) {
					if( !(( i == 2 )&&( j == 2 )) && myMap[Top+i][Left+j] != '&') {
						myMap[Top+i][Left+j] = view[i][j];
					}
				}
			}
		} else if (agentDirection == 0){
			int i, j;
			for(i = 0; i < 5; i++) {
				for(j = 0; j < 5; j++) {
					if( !(( i == 2 )&&( j == 2 )) && myMap[Bottom-j][Left+i] != '&') {
						myMap[Bottom-j][Left+i] = view[i][j];
					}
				}
			}
		}else if (agentDirection == 2) {
			int i, j;
			for(i = 0; i < 5; i++) {
				for(j = 0; j < 5; j++) {
					if( !(( i == 2 )&&( j == 2 )) && myMap[Top+j][Right-i] != '&') {
						myMap[Top+j][Right-i] = view[i][j];
					}
				}
			} 
		}else {
			int i, j;
			for(i = 0; i < 5; i++) {
				for(j = 0; j < 5; j++) {
					if( !(( i == 2 )&&( j == 2 ))&&myMap[Bottom-i][Right-j]!='&') {
						myMap[Bottom-i][Right-j] = view[i][j];
					}
				}
			}
		}
	}

	public char[][] getMyMap() {
		return myMap;
	}

	public void setMyMap(char myMap[][]) {
		this.myMap = myMap;
	}
	
	public char getPosition(int i, int j) {
		return myMap[i][j];
	}

	public void setPosition(int i, int j, char content){
		myMap[i][j] = content;
	}
	
	public char getContentAtPosition(Position p){
		return myMap[p.i][p.j];
	}
	
	public Position findGoal(char goal){
		Position p = null;
		int i,j;
		for(i = 0; i < 160; i++) {
			for (j = 0; j < 160; j++) {
				if (myMap[i][j]==goal){
					p = new Position (i, j);
				}
			}
		}
		return p;
	}
	
	public ArrayList<Position> findAllGoals(char goal){
		ArrayList<Position> positions = new ArrayList<Position>();
		for(int i = 0; i < 160; i++) {
			for (int j = 0; j < 160; j++) {
				if (myMap[i][j]==goal){
					Position p = new Position (i, j);
					positions.add(p);
				}
			}
		}
		return positions;
	}
	
	public int shortestDistanceToGold(){
		Position[][] tempConversion = new Position[160][160];
		
		for (int i = 0; i < 160; i++){
			for (int j = 0; j< 160; j ++){
				tempConversion[i][j] =new Position(i, j); 
			}
		}
		
		Position gold = findGoal('g');
		gold.added = true;
		gold.shortestPathToGold = 0;
		
		int shortestDistance = 0;
		Queue<Position> toCheck = new LinkedList<Position>();
		toCheck.add(gold);
		
		while (shortestDistance == 0){
			Position removed = toCheck.remove();
			if (getContentAtPosition(removed)==' '){
				shortestDistance = removed.shortestPathToGold;
			}
			
			ArrayList<Position> adjacentPositions = new ArrayList<Position>();
			adjacentPositions.add(new Position(removed.i-1, removed.j, removed.shortestPathToGold+1));
			adjacentPositions.add(new Position(removed.i+1, removed.j, removed.shortestPathToGold+1));
			adjacentPositions.add(new Position(removed.i, removed.j-1, removed.shortestPathToGold+1));
			adjacentPositions.add(new Position(removed.i, removed.j+1, removed.shortestPathToGold+1));
			
			for (Position p : adjacentPositions){
				if (p.added == false){
					p.added = true;
					toCheck.add(p);
				}
			}
		}
		return shortestDistance;
	}
}
